/*****************************************************************************
*    Copyright (C)2003 Ali Corporation. All Rights Reserved.
*
*    File:    nim_ix2476.c
*
*    Description:    This file contains ix2476 basic function in LLD for Sharp 0184 module.
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.  Jan.28.2004		David Wang		Ver 0.1		Create file.
*****************************************************************************/

#include <sys_config.h>


#include <retcode.h>
#include <types.h>

#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>

#include "nim_ix2476.h"

static unsigned char init_data[] =
{
    0x04,
    0x7E,
    0xE1,	//PD5~4=TM=RTS=0
    0xE2	//PD3~2=0
};

struct QPSK_TUNER_CONFIG_EXT * stIX2476_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stIX2476_tuner_cnt = 0;
/*****************************************************************************
* INT32 nim_ix2476_init(UINT32 para, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* TunerIX2476 Initialization
*
* Arguments:
*  Parameter1: UINT32 para		: Input Parameter
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2476_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	INT32	result = 200;
	struct QPSK_TUNER_CONFIG_EXT * stIX2476_ptr = NULL;
	//soc_printf("enter nim_ix2476_init \n");
	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stIX2476_tuner_cnt>MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stIX2476_ptr = (struct QPSK_TUNER_CONFIG_EXT *)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stIX2476_ptr)
		return ERR_FAILUE;
	stIX2476_dev_id[stIX2476_tuner_cnt] = stIX2476_ptr;
	MEMCPY(stIX2476_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	*tuner_id = stIX2476_tuner_cnt;
	stIX2476_tuner_cnt++;
/*	soc_printf("%s: sizeof QPSK_TUNER_CONFIG_EXT = %d\n", __FUNCTION__, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	soc_printf("Base Address: 0x%x\n",stIX2476_Config.cTuner_Base_Addr);
	soc_printf("Tuner Crystal: %dKHz\n",stIX2476_Config.wTuner_Crystal);
	soc_printf("Output Mode: %d (1 -- Signle End; 0 -- Differential)\n",stIX2476_Config.cTuner_Out_S_D_Sel);
*/
	result = i2c_write(stIX2476_ptr->i2c_type_id, stIX2476_ptr->cTuner_Base_Addr, init_data, sizeof(init_data));

    return result;
}

/*****************************************************************************
* INT32 nim_ix2476_control(UINT32 freq, UINT16 bs, UINT8 cp)
*
* Tuner write operation
*
* Arguments:
*  Parameter1: UINT32 freq		: Synthesiser programmable divider
*  Parameter2: UINT8 bs			: Baseband path select
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2476_control(UINT32 tuner_id, UINT32 freq, UINT16 bs)
{
	UINT8 data[4];
	UINT16 Npro,tmp;
	UINT32 Rs, BW;
	UINT8 Nswa;
	UINT8 LFP = 15;
	UINT8 BA = 1;
	UINT8 DIV = 0;
	INT32 result;
	struct QPSK_TUNER_CONFIG_EXT * stIX2476_ptr = NULL;
	if(tuner_id>=stIX2476_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stIX2476_ptr = stIX2476_dev_id[tuner_id];
	/* LFP cut_off */
	Rs = bs;
	if (Rs==0)
		Rs = 45000;
	BW = Rs*135/200;                // rolloff factor is 35%
	BW = BW*130/100;                // 0.1dB to 3dB need about 30% transition band for 7th order LPF
	if (Rs<6500)  BW = BW + 3000;   // add 3M when Rs<5M, since we need shift 3M to avoid DC
	BW = BW + 2000;                 // add 2M for LNB frequency shifting
//ZCY: the cutoff freq of IX2410 is not 3dB point, it more like 0.1dB, so need not 30%
	//BW = BW*130/100;                // 0.1dB to 3dB need about 30% transition band for 7th order LPF
	BW = BW*108/100;                // add 8% margin since fc is not very accurate
//	if (BW< 10000)   BW =  10000;     // Sharp2476 LPF can be tuned form 10M to 30M, step is 2.0M
//	if (BW>30000)   BW = 30000;     // the range can be 6M~~34M actually, 4M is not good

	if (BW<=10000)  LFP = 0x0c;
	else if (BW<=12000)  LFP = 0x02;
	else if (BW<=14000)  LFP = 0x0a;
	else if (BW<=16000)  LFP = 0x06;
	else if (BW<=18000)  LFP = 0x0e;
	else if (BW<=20000)  LFP = 0x01;
	else if (BW<=22000)  LFP = 0x09;
	else if (BW<=24000)  LFP = 0x05;
	else if (BW<=26000)  LFP = 0x0d;
	else if (BW<=28000)  LFP = 0x03;
	else				  LFP = 0x0b;
//	soc_printf (" Sharp Tuner Parameter:\n");
//	soc_printf ("    Rs  = %d\n", bs);
//	soc_printf ("    BW  = %d\n", BW);
//	soc_printf ("    LFP = %d\n", LFP);


	/* local oscillator select */
	DIV = 0;
	if(freq <= 2150)
		BA = 6;
	if(freq <= 1942)
		BA = 5;
	if(freq <= 1778)
		BA = 4;
	if(freq <= 1607)
		BA = 3;
	if(freq <= 1445)
		BA = 2;
	if(freq <= 1300)
		BA = 1;
	if(freq <= 1170)
	{
		BA = 7;
		DIV = 1;
	}
	if(freq <= 1065)
	{
		BA = 6;
		DIV = 1;
	}
	//PRINTF("freq = %d,bs = %d\n",freq,bs);
	//PRINTF("BA:%d,LFP:%d,DIV:%d\n",BA,LFP,DIV);

	tmp = freq * 1000 * 8 / stIX2476_ptr->wTuner_Crystal;
	Nswa = tmp % 32;						//PSC=0
	Npro = tmp / 32;
	//PRINTF("Npro = %d,Nswa = %d\n",Npro,Nswa);

	data[0] = (UINT8) ((Npro>>3)&0x7F);		//BG1:0=00
	data[1] = Nswa | (((UINT8)Npro&0x07) << 5);
	data[2] = 0xE1;						//C1:0=11,TM=0
	data[3] = (BA<<5) | (DIV<<1);
	i2c_write(stIX2476_ptr->i2c_type_id, stIX2476_ptr->cTuner_Base_Addr, data+0, 4);

	data[2] = 0xE5;						//TM=1

	i2c_write(stIX2476_ptr->i2c_type_id, stIX2476_ptr->cTuner_Base_Addr, data+2, 1);
	osal_delay(20000);

	data[2] |= (LFP&0x0c)<<1;
	data[3] |= (LFP&0x03)<<2;

	i2c_write(stIX2476_ptr->i2c_type_id, stIX2476_ptr->cTuner_Base_Addr, data+2, 2);

	//PRINTF("%Tuner: %x,%x,%x,%x\n",data[0],data[1],data[2],data[3]);
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_ix2476_status(UINT8 *lock)
*
* Tuner read operation
*
* Arguments:
*  Parameter1: UINT8 *lock		: Phase lock status
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2476_status(UINT32 tuner_id, UINT8 *lock)
{
	INT32 result;
	UINT8 data[1];
	struct QPSK_TUNER_CONFIG_EXT * stIX2476_ptr = NULL;
	if(tuner_id>=stIX2476_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	stIX2476_ptr = stIX2476_dev_id[tuner_id];
	result = i2c_write_read(stIX2476_ptr->i2c_type_id, stIX2476_ptr->cTuner_Base_Addr, data, 0, 1);
	*lock = ((data[0] & 0x40) >> 6);

	return result;
}

